﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace eslib.nnp5
{
    /// <summary>
    /// TCP连接对象
    /// </summary>
    public class TCPConnector : Connector
    {
        #region 属性

        /// <summary>
        /// 绑定的Tcp客户端
        /// </summary>
        TcpClient TcpClient { get; set; }


        /// <summary>
        /// 绑定的网络流
        /// </summary>
        NetworkStream Stream { get; set; }


        /// <summary>
        /// 缓冲区长度
        /// </summary>
        public int BufferLength { get; set; }

        /// <summary>
        /// 缓冲区
        /// </summary>
        byte[] Buffer { get; set; }

        #endregion



        /// <summary>
        /// 新建连接器-客户端构造
        /// </summary>
        /// <param name="host">主机地址</param>
        /// <param name="port">端口</param>
        /// <param name="bufLen">缓冲区长度</param>
        public TCPConnector(string host, int port, int bufLen = 4096)
        {
            this.host = host;
            this.port = port;

            this.BufferLength = bufLen;
            this.Buffer = new byte[BufferLength];
        }



        /// <summary>
        /// 同步连接，不会引发事件，连接失败时引发事件
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public override bool connect()
        {
            try
            {
                TcpClient = new TcpClient(AddressFamily.InterNetwork);
                TcpClient.Connect(host, port);
                Stream = TcpClient.GetStream();

                //启动读取
                BeginRead();

                return true;
            }
            catch (Exception ex)
            {
                InvokeConnectFailEvent(ex.Message);
                return false;
            }
        }



        /// <summary>
        /// 克隆连接器（只复制连接信息,host,port），返回TCPConnector
        /// </summary>
        /// <returns></returns>
        public override Connector Clone()
        {
            TCPConnector conn = new TCPConnector(this.host, this.port, this.BufferLength);
            return conn;
        }


        /// <summary>
        /// 异步连接
        /// </summary>
        public override void beginConnect()
        {
            try
            {
                TcpClient = new TcpClient(AddressFamily.InterNetwork);
                TcpClient.BeginConnect(host, port, new AsyncCallback(connCallback), null);
            }
            catch (Exception err)
            {
                InvokeConnectFailEvent(err.Message);
            }
        }



        #region 自动重连


        string host;
        int port;

        /// <summary>
        /// 重新连接
        /// </summary>
        public override void reConnect()
        {
            beginConnect();
        }


        #endregion







        private void connCallback(IAsyncResult ar)
        {
            try
            {
                TcpClient.EndConnect(ar);
                Stream = TcpClient.GetStream();

                //启动读取
                BeginRead();

                InvokeConnectSuccesEvent();
            }
            catch (Exception ex)
            {
                //连接不上
                InvokeConnectFailEvent(ex.Message);
            }
        }







        /// <summary>
        /// 由ServerListener构造
        /// </summary>
        /// <param name="newClient"></param>
        /// <param name="bufLen">缓冲区长度</param>
        public TCPConnector(TcpClient newClient, int bufLen)
        {
            try
            {
                this.TcpClient = newClient;
                Stream = TcpClient.GetStream();

                this.BufferLength = bufLen;
                this.Buffer = new byte[BufferLength];

                //启动读取
                BeginRead();
            }
            catch (Exception ex)
            {
                throw new CommunicaException(ex.Message);
            }


        }



        /// <summary>
        /// 发送
        /// </summary>
        /// <param name="buffer"></param>
        public override void send(byte[] buffer)
        {
            lock (this)     //线程同步（防止顺序打乱）
            {
                Stream.Write(buffer, 0, buffer.Length);
                Stream.Flush();
            }
        }



        /// <summary>
        /// 启动读取线程
        /// </summary>
        private void BeginRead()
        {
            //使用ReadAsync实现
            Task.Run(BeginReadData);

            //Stream.BeginRead(Buffer, 0, BufferLength, new AsyncCallback(ReadCallback), null);   //启动读取线程
        }

        private void BeginReadData()
        {
            cancelRead = new CancellationTokenSource();

            Task.Run(async () =>
            {
                while (!cancelRead.IsCancellationRequested)
                {
                    int len = await Stream.ReadAsync(Buffer, 0, BufferLength, cancelRead.Token);
                    if (len == 0) break;

                    List<byte> bufLst = new List<byte>();
                    bufLst.AddRange(Buffer);
                    byte[] outBuf = bufLst.GetRange(0, len).ToArray();

                    Buffer = new byte[BufferLength];        //缓冲区初始化

                    InvokeRecvEvent(outBuf, len);
                }
            });
        }
        CancellationTokenSource cancelRead;

        //private void ReadCallback(IAsyncResult ar)
        //{
        //    try
        //    {
        //        int len = Stream.EndRead(ar);
        //        if (len == 0) throw new NNP6Exception("接收到数据的长度为0");

        //        List<byte> bufLst = new List<byte>();
        //        bufLst.AddRange(Buffer);
        //        byte[] outBuf = bufLst.GetRange(0, len).ToArray();

        //        Buffer = new byte[BufferLength];        //缓冲区初始化

        //        InvokeRecvEvent(outBuf, len);

        //        //【关键点】必需先执行完上层事件，再重新开始BeginRead.否则会因线程问题引起错误
        //        Stream.BeginRead(Buffer, 0, BufferLength, new AsyncCallback(ReadCallback), null);   //继续读取                                 
        //    }
        //    catch (Exception er)
        //    {
        //        InvokeDisconnectEvent(string.Format("{0} - {1}", er.GetType(), er.Message));
        //    }
        //}






        /// <summary>
        /// 关闭连接
        /// </summary>
        public override void close()
        {
            try
            {
                Stream.Close();
                Stream.Dispose();
                TcpClient.Close();
            }
            catch { }
        }

    }
}
